home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / netbsd / tools / dcp-1.1.lha / dcp.c < prev    next >
C/C++ Source or Header  |  1993-10-14  |  15KB  |  555 lines

  1. /*
  2.  * File/Device copier by Chris Hooper (cdh@mtu.edu) on  5-Jul-93  v1.0
  3.  *                               14-Oct-93  v1.1
  4.  *
  5.  *    This program can copy files to devices and devices to files, etc.
  6.  *
  7.  * Usage:
  8.  *    dcp {source} {dest} [-m number of blocks] [-b buffer size] [-v verbose]
  9.  *              [-ss source start block] [-ds dest start block]
  10.  *              [-d dryrun] [-h help]
  11.  *
  12.  * This product is distributed as freeware with no warrantees expressed or
  13.  * implied.  There are no restrictions on distribution or application of
  14.  * this program other than it may not be used in contribution with or
  15.  * converted to an application under the terms of the GNU Public License
  16.  * nor sold for profit greater than the cost of distribution.  Also, this
  17.  * notice must accompany all redistributions and/or modifications of this
  18.  * program.  Remember:  If you expect bugs, you should not be disappointed.
  19.  *
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <exec/types.h>
  24. #include <devices/trackdisk.h>
  25. #include <libraries/dos.h>
  26. #include <dos/dosextens.h>
  27. #include <dos/filehandler.h>
  28. #include <exec/io.h>
  29. #include <fcntl.h>
  30. #include <sys/stat.h>
  31. #include <exec/memory.h>
  32.  
  33. /*    #define DEBUG(x) fprintf(stderr, x)    */
  34.  
  35. /* Possible file types
  36.  *    tNONE   0 = Could not be opened
  37.  *    tDEVICE 1 = Block device opened
  38.  *    tFILE   2 = Regular AmigaDOS file opened
  39.  *    tSTDIO  3 = STDIO channel specified 
  40.  */
  41. #define tNONE     0
  42. #define tDEVICE    1
  43. #define tFILE     2
  44. #define tSTDIO     3
  45.  
  46. #define dREAD  0
  47. #define dWRITE 1
  48.  
  49. /* BCPL conversion functions */
  50. #define BTOC(x) ((x)<<2)
  51. #define CTOB(x) ((x)>>2)
  52.  
  53. /* quick parameter parser */
  54. #define ACCEPT(x,y)                                \
  55.     if (!strcmp(argv[index], y)) {                        \
  56.         index++;                                \
  57.         if (index < argc) {                            \
  58.             x = atoi(argv[index]);                        \
  59.             if (x < 1) {                            \
  60.             fprintf(stderr, "number required for %s parameter\n", y);    \
  61.             exit(1);                            \
  62.             }                                \
  63.         } else {                                \
  64.             fprintf(stderr, "number required for %s parameter\n", y);    \
  65.             exit(1);                            \
  66.         }                                    \
  67.     }
  68.  
  69.  
  70. char *strchr();
  71. struct FileSysStartupMsg *find_startup();
  72.  
  73.  
  74. struct file_info {
  75.     char    *name;          /* filename as specified on cmdline */
  76.     int    dtype;          /* NONE, DEVICE, FILE, or STDIO */
  77.     FILE    *strIO;          /* stream file pointer */
  78.     struct    IOExtTD *trackIO; /* device packet pointer */
  79.     ULONG    currentblk;      /* current read/write block in device/file */
  80.     ULONG    maxblk;          /* maximum allowed read/write blk in dev/file */
  81. };
  82.  
  83.  
  84. struct file_info in;        /* internal input file descriptor */
  85. struct file_info out;        /* internal output file descriptor */
  86.  
  87. char    *progname;        /* name of this program running */
  88. char    iobuf[128];        /* buffer for line-oriented I/O */
  89. char    *version = "1.1";    /* program revision */
  90. char    *revdate = "14-Oct-93";    /* program revision date */
  91. int    last_read_blocks;    /* number of blocks last read */
  92. char    *buffer    = NULL;        /* buffer area for copy operations */
  93. int    buffer_blocks = 2000;    /* size of buffer area */
  94. int    verbose       = 0;    /* verbose mode  - default = off */
  95. int    dryrun        = 0;    /* dryrun mode   - default = off */
  96. ULONG    maxblk        = 0;    /* maximum block - default = none */
  97. ULONG    source_start  = 0;    /* src start blk - default = zero */
  98. ULONG    dest_start    = 0;    /* dst start blk - default = zero */
  99.  
  100.  
  101. main(argc, argv)
  102. int argc;
  103. char *argv[];
  104. {
  105.     int names = 0;
  106.     int index;
  107.  
  108.     progname = argv[0];
  109.  
  110.     setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf));
  111.  
  112.     if (argc == 1)
  113.         print_usage();
  114.  
  115.     for (index = 1; index < argc; index++) {
  116.         ACCEPT(maxblk, "-m")
  117.         else ACCEPT(buffer_blocks, "-b")
  118.         else ACCEPT(source_start, "-ss")
  119.         else ACCEPT(dest_start, "-sd")
  120.         else ACCEPT(dest_start, "-ds")
  121.         else if (!strcmp(argv[index], "-v"))
  122.             verbose++;
  123.         else if (!strcmp(argv[index], "-h"))
  124.             print_help();
  125.         else if (!strcmp(argv[index], "-d"))
  126.             dryrun++;
  127.         else {
  128.             names++;
  129.             if (names == 1)
  130.             in.name  = argv[index];
  131.             else if (names == 2)
  132.             out.name = argv[index];
  133.             else {
  134.             fprintf(stderr, "unknown parameter %s\n", argv[index]);
  135.             exit(1);
  136.             }
  137.         }
  138.     }
  139.  
  140.     if (names != 2) {
  141.         printf("Source and destination are required for %s\n", progname);
  142.         exit(1);
  143.     }
  144.  
  145.     if (maxblk && (buffer_blocks > maxblk))
  146.         buffer_blocks = maxblk;
  147.  
  148.     while ((buffer == NULL) && (buffer_blocks)) {
  149.         buffer = (char *) AllocMem(buffer_blocks *
  150.                          TD_SECTOR, MEMF_PUBLIC);
  151.         if (buffer == NULL)
  152.             buffer_blocks >>= 1;
  153.     }
  154.  
  155.     if (buffer == NULL) {
  156.         fprintf(stderr, "Unable to allocate even 1 block for copy buffer!\n");
  157.         exit(1);
  158.     }
  159.  
  160.     do_open(&in,  dREAD);
  161.     do_open(&out, dWRITE);
  162.  
  163.     set_limits(&in, &out);
  164.  
  165.     if ((in.dtype != tNONE) && (out.dtype != tNONE))
  166.         while (do_io(&in, dREAD))
  167.             if (do_io(&out, dWRITE) == 0)
  168.                 break;
  169.  
  170.     if (verbose)
  171.         fprintf(stderr, "\n");
  172.  
  173.     do_close(&in);
  174.     do_close(&out);
  175.  
  176.     FreeMem(buffer, buffer_blocks * TD_SECTOR);
  177.  
  178.     exit(0);
  179. }
  180.  
  181. do_open(fdes, dtype)
  182. struct file_info *fdes;
  183. int dtype;
  184. {
  185.     int len;
  186.     char *pos;
  187.  
  188.     fdes->currentblk = 0;        /* start at beginning */
  189.     fdes->maxblk = 0;        /* no maximum block */
  190.  
  191.     if (verbose)
  192.         if (dtype == dREAD)
  193.             fprintf(stderr, "R ");
  194.         else
  195.             fprintf(stderr, "W ");
  196.  
  197.     if (!strcmp(fdes->name, "-")) {        /* stdio */
  198.         fdes->dtype = tSTDIO;
  199.         if (dtype == dREAD)
  200.             fdes->strIO = stdin;
  201.         else
  202.             fdes->strIO = stdout;
  203.         if (verbose)
  204.             fprintf(stderr, "STDIO %s\n", fdes->name);
  205.         return;
  206.     }
  207.  
  208.     len = strlen(fdes->name);
  209.     if (len == 0) {
  210.         fprintf(stderr, "Error opening file for %s.\n",
  211.             (dtype == dREAD) ? "read" : "write");
  212.         return;
  213.     }
  214.  
  215.     pos = strchr(fdes->name, ',');
  216.  
  217.     if (!pos && (fdes->name[len - 1] != ':')) {    /* must be a file */
  218.         if (dtype == dREAD) {
  219.         struct stat stat_buf;
  220.         if (!stat(fdes->name, &stat_buf))
  221.             fdes->maxblk = (stat_buf.st_size + TD_SECTOR - 1) / TD_SECTOR;
  222.         }
  223.         if (!dryrun)    
  224.             fdes->strIO = fopen(fdes->name, (dtype == dREAD) ? "r" : "w");
  225.         if ((fdes->strIO == NULL) && !dryrun) {
  226.         fprintf(stderr, "Error opening file %s for %s.\n",
  227.             fdes->name, (dtype == dREAD) ? "read" : "write");
  228.         fdes->dtype = tNONE;
  229.         } else {
  230.         fdes->dtype = tFILE;
  231.         if (verbose) {
  232.             fprintf(stderr, "file %-40s", fdes->name);
  233.             fprintf(stderr, "start=%-7d  ", fdes->currentblk);
  234.             fprintf(stderr, "end=%-7d\n", fdes->maxblk);
  235.         }
  236.         }
  237.     } else {                /* must be a device */
  238.         struct FileSysStartupMsg *startup;
  239.         struct DosEnvec *envec;
  240.         char *disk_device;
  241.         int disk_unit, disk_flags;
  242.  
  243.         if (!(fdes->trackIO = (struct IOExtTD *)
  244.         CreateExtIO(CreatePort(0, 0), sizeof(struct IOExtTD)) )) {
  245.         fprintf(stderr, "Failed to create trackIO structure for %s.\n", fdes->name);
  246.         return;
  247.         }
  248.  
  249.         if (pos) {
  250.         char *pos2;
  251.  
  252.         disk_device = fdes->name;
  253.         disk_flags  = 0;
  254.  
  255.         *pos = '\0';
  256.         
  257.         if (isdigit(pos + 1)) {
  258.             disk_unit = atoi(pos + 1);
  259.             pos2 = strchr(pos + 1, ",");
  260.             if (pos2)
  261.             disk_flags = atoi(pos2 + 1);
  262.         } else {
  263.             fprintf(stderr, "Error opening device %s for %s; you must specify a unit number!\n",
  264.                 fdes->name, (dtype == dREAD) ? "read" : "write");
  265.             fdes->dtype = tNONE;
  266.             return;
  267.         }
  268.         fdes->currentblk = 0;
  269.         fdes->maxblk     = 0;
  270.         } else {
  271.         startup = find_startup(fdes->name);
  272.         if (startup == NULL) {
  273.             fprintf(stderr, "Error opening device %s for %s; does not exist\n",
  274.                 fdes->name, (dtype == dREAD) ? "read" : "write");
  275.             fdes->dtype = tNONE;
  276.             return;
  277.         }
  278.  
  279.         disk_device      = ((char *) BTOC(startup->fssm_Device)) + 1;
  280.         disk_unit        = startup->fssm_Unit;
  281.         disk_flags       = startup->fssm_Flags;
  282.         envec            = (struct DosEnvec *) BTOC(startup->fssm_Environ);
  283.         fdes->currentblk = envec->de_LowCyl * envec->de_Surfaces *
  284.                    envec->de_BlocksPerTrack;
  285.         fdes->maxblk     = envec->de_HighCyl * envec->de_Surfaces *
  286.                    envec->de_BlocksPerTrack;
  287.         }
  288.  
  289.         if (verbose) {
  290.         char buf[40];
  291.         sprintf(buf, "%s=%s", fdes->name, disk_device);
  292.         fprintf(stderr, "dev  %-21s ", buf);
  293.         fprintf(stderr, "unit=%-2d  ", disk_unit);
  294.         fprintf(stderr, "flag=%-2d  ", disk_flags);
  295.         fprintf(stderr, "start=%-7d  ", fdes->currentblk);
  296.         fprintf(stderr, "end=%-7d\n", fdes->maxblk);
  297.         }
  298.  
  299.         if (OpenDevice(disk_device, disk_unit, fdes->trackIO, disk_flags)) {
  300.         fprintf(stderr, "fatal: Unable to open %s unit %d for %s.\n",
  301.             disk_device, disk_unit, fdes->name);
  302.         DeletePort(fdes->trackIO->iotd_Req.io_Message.mn_ReplyPort);
  303.         DeleteExtIO(fdes->trackIO);
  304.         return;
  305.         }
  306.  
  307.         fdes->trackIO->iotd_Req.io_Command  = (dtype == dREAD) ?
  308.                         CMD_READ : CMD_WRITE;
  309.         fdes->trackIO->iotd_Req.io_Data        = buffer;
  310.  
  311.         fdes->dtype = tDEVICE;
  312.  
  313.         if (pos)
  314.         *pos = ',';
  315.     }
  316. }
  317.  
  318.  
  319. set_limits(in, out)
  320. struct file_info *in;
  321. struct file_info *out;
  322. {
  323.     if (maxblk) {
  324.         if (in->maxblk > maxblk)
  325.             in->maxblk = maxblk;
  326.         if (out->maxblk > maxblk)
  327.             out->maxblk = maxblk;
  328.     }
  329.  
  330.     if (source_start)
  331.         in->currentblk += source_start;
  332.  
  333.     if (dest_start)
  334.         out->currentblk += dest_start;
  335.  
  336.     if (in->maxblk && (in->currentblk > in->maxblk))
  337.         in->dtype = tNONE;
  338.  
  339.     if (out->maxblk && (out->currentblk > out->maxblk))
  340.         out->dtype = tNONE;
  341.  
  342.     if (!dryrun && (in->dtype == tFILE) && (in->dtype != tNONE))
  343.         fseek(in->strIO, in->currentblk * TD_SECTOR, SEEK_SET);
  344.  
  345.     if (!dryrun && (out->dtype == tFILE) && (out->dtype != tNONE))
  346.         fseek(out->strIO, out->currentblk * TD_SECTOR, SEEK_SET);
  347. }
  348.  
  349. struct FileSysStartupMsg *find_startup(name)
  350. char *name;
  351. {
  352.     struct    DosLibrary *DosBase;
  353.     struct    RootNode *rootnode;
  354.     struct    DosInfo *dosinfo;
  355.     struct    DevInfo *devinfo;
  356.     struct    DosEnvec *envec;
  357.     static  struct FileSysStartupMsg *startup;
  358.     char    *devname;
  359.     char    *pos;
  360.     int    notfound = 1;
  361.  
  362.     if ((pos = strchr(name, ':')) != NULL)
  363.         *pos = '\0';
  364.  
  365.     DosBase = (struct DosLibrary *) OpenLibrary("dos.library", 0L);
  366.  
  367.     rootnode= DosBase->dl_Root;
  368.     dosinfo = (struct DosInfo *) BTOC(rootnode->rn_Info);
  369.     devinfo = (struct DevInfo *) BTOC(dosinfo->di_DevInfo);
  370.  
  371.     while (devinfo != NULL) {
  372.         devname    = (char *) BTOC(devinfo->dvi_Name);
  373.         if (unstrcmp(devname + 1, name)) {
  374.             notfound = 0;
  375.             break;
  376.         }
  377.         devinfo    = (struct DevInfo *) BTOC(devinfo->dvi_Next);
  378.     }
  379.  
  380.     if (notfound) {
  381.         fprintf(stderr, "%s: is not mounted.\n", name);
  382.         exit(1);
  383.     }
  384.  
  385.     startup    = (struct FileSysStartupMsg *) BTOC(devinfo->dvi_Startup);
  386.     CloseLibrary(DosBase);
  387.     return(startup);
  388. }
  389.  
  390. /* unsigned string compare */
  391. int unstrcmp(str1, str2)
  392. char *str1;
  393. char *str2;
  394. {
  395.     while (*str1 != '\0') {
  396.         if (*str2 == '\0')
  397.             break;
  398.         else if (*str1 != *str2)
  399.             if ((*str1 >= 'A') && (*str1 <= 'Z')) {
  400.                 if ((*str2 >= 'A') && (*str2 <= 'Z'))
  401.                     break;
  402.                 else if (*str1 != *str2 + 'A' - 'a')
  403.                     break;
  404.             } else {
  405.                 if ((*str2 >= 'a') && (*str2 <= 'a'))
  406.                     break;
  407.                 else if (*str1 != *str2 - 'A' + 'a')
  408.                     break;
  409.             }
  410.         str1++;
  411.         str2++;
  412.     }
  413.     if (*str1 == *str2)
  414.         return(1);
  415.     else
  416.         return(0);
  417. }
  418.  
  419. do_close(fdes)
  420. struct file_info *fdes;
  421. {
  422.     if (fdes->dtype == tSTDIO)
  423.         return;
  424.     else if (fdes->dtype == tFILE) {
  425.         if (!dryrun)
  426.             fclose(fdes->strIO);
  427.     } else if (fdes->dtype == tDEVICE)
  428.         if (fdes->trackIO != NULL) {
  429.             CloseDevice(fdes->trackIO);
  430.             DeletePort(fdes->trackIO->iotd_Req.io_Message.mn_ReplyPort);
  431.             DeleteExtIO(fdes->trackIO);
  432.         }
  433. }
  434.  
  435.  
  436. do_io(fdes, dtype)
  437. struct file_info *fdes;
  438. int dtype;
  439. {
  440.     int io_left = 0;
  441.     int last_write_blks;
  442.  
  443.     if (dtype == dREAD) {
  444.         io_left = buffer_blocks;
  445.  
  446.         if (fdes->maxblk)
  447.             if ((fdes->maxblk - fdes->currentblk) < io_left)
  448.                 io_left = fdes->maxblk - fdes->currentblk;
  449. #ifdef DEBUG
  450.         fprintf(stderr, "tran=R blocks=%d cur=%d max=%d left=%d\n",
  451.             buffer_blocks, fdes->currentblk, fdes->maxblk, io_left);
  452. #endif
  453.         if (io_left < 1)
  454.             return(0);
  455.     } else {
  456.         io_left = last_read_blocks;
  457.  
  458.         if (fdes->maxblk)
  459.             if ((fdes->maxblk - fdes->currentblk) < io_left)
  460.                 io_left = fdes->maxblk - fdes->currentblk;
  461. #ifdef DEBUG
  462.         fprintf(stderr, "tran=W blocks=%d cur=%d max=%d left=%d\n",
  463.             buffer_blocks, fdes->currentblk, fdes->maxblk, io_left);
  464. #endif
  465.         if (io_left < 1)
  466.             return(0);
  467.     }
  468.  
  469.     if (verbose) {
  470.         setvbuf(stderr, NULL, _IONBF, 0);
  471.         fprintf(stderr, "%s at %-7d  count=%d%5s\r",
  472.             (dtype == dREAD) ? "Read " : "Write",
  473.             fdes->currentblk, io_left, "");
  474. #ifdef DEBUG
  475.         fprintf(stderr, "\n");
  476. #endif
  477.         setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf));
  478.     }
  479.  
  480.     if ((fdes->dtype == tDEVICE) && !dryrun) {
  481.         fdes->trackIO->iotd_Req.io_Length = io_left * TD_SECTOR;
  482.         fdes->trackIO->iotd_Req.io_Offset = fdes->currentblk * TD_SECTOR;
  483.         DoIO(fdes->trackIO);
  484.         if (dtype == dREAD)
  485.         last_read_blocks = io_left;
  486.     } else if (!dryrun) {            /* Must be either file or stdio */
  487.         if (dtype == dREAD)
  488.         last_read_blocks = fread(buffer, TD_SECTOR, io_left, fdes->strIO);
  489.         else if ((last_write_blks = fwrite(buffer, TD_SECTOR, io_left,
  490.                                fdes->strIO)) != io_left) {
  491.         if (last_write_blks >= 0)
  492.             fprintf(stderr, "destination full before source exhausted.\n");
  493.         else
  494.             fprintf(stderr, "failure: write did not finish normally\n");
  495.         return(0);
  496.         }
  497.     } else if (dtype == dREAD)
  498.         last_read_blocks = io_left;
  499.  
  500.     fdes->currentblk += io_left;
  501.  
  502.     return(1);
  503. }
  504.  
  505.  
  506. print_usage()
  507. {
  508.     int len;
  509.  
  510.     setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf));
  511.  
  512.     len = strlen(progname) + 9;
  513.     fprintf(stderr, "%s %s by Chris Hooper on %s\n",
  514.         progname, version, revdate);
  515.     fprintf(stderr, "Usage: %s [options] {source} {dest}\n", progname);
  516.     fprintf(stderr, "%*s -b = specify buffer size\n", len, "");
  517.     fprintf(stderr, "%*s -m = specify maximum blocks to transfer\n", len, "");
  518.     fprintf(stderr, "%*s-ss = specify source block number at which to start\n", len, "");
  519.     fprintf(stderr, "%*s-ds = specify destination block number at which to start\n", len, "");
  520.     fprintf(stderr, "%*s -v = turn on verbose mode\n", len, "");
  521.     fprintf(stderr, "%*s -h = give more help\n", len, "");
  522.     exit(1);
  523. }
  524.  
  525. print_help()
  526. {
  527.     setvbuf(stderr, iobuf, _IOLBF, sizeof(iobuf));
  528.  
  529.     fprintf(stderr, "%s is a program which will does block copies from the specified source\n", progname);
  530.     fprintf(stderr, "to the specified destination.  The source and destination may each\n");
  531.     fprintf(stderr, "independently be either a file or a block device.\n");
  532.     fprintf(stderr, "\n");
  533.     fprintf(stderr, "The source and destination are specified as filenames.  A device is\n");
  534.     fprintf(stderr, "differentiated from a file as having a colon (:) as the last character\n");
  535.     fprintf(stderr, "of the filename.  A device may also be specified by giving the Amiga\n");
  536.     fprintf(stderr, "device information, separated by commas (,).  The source is always\n");
  537.     fprintf(stderr, "specified first.  WARNING: A comma makes it a device!");
  538.     fprintf(stderr, "\n");
  539.     fprintf(stderr, "Examples of usage:\n");
  540.     fprintf(stderr, "\n");
  541.     fprintf(stderr, "Copy file \"unix_fs\" from dh0: and overwrite df0: with that file\n");
  542.     fprintf(stderr, "\t%s dh0:unix_fs df0:\n", progname);
  543.     fprintf(stderr, "\n");
  544.     fprintf(stderr, "Copy 8192 blocks from raw SCSI disk, unit 6 starting at block 16384\n");
  545.     fprintf(stderr, "and write that to file \"junk\" in current directory\n");
  546.     fprintf(stderr, "\t%s -ss 16384 -m 8192 scsi.device,6 junk\n", progname);
  547.     fprintf(stderr, "\n");
  548.     fprintf(stderr, "Copy partition BSDR: to a file \"BSD_root\"\n");
  549.     fprintf(stderr, "\t%s bsdr: BSD_root\n", progname);
  550.     fprintf(stderr, "\n");
  551.     fprintf(stderr, "Copy first five blocks from partition BAK: to block 1532 in partition TEST:\n");
  552.     fprintf(stderr, "\t%s -m 5 -ds 1532 BAK: Test:\n", progname);
  553.     exit(1);
  554. }
  555.